package se.study.jdbc;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidPooledConnection;

import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

/**
 * @Author: tiger
 * @Date:2018/5/23
 * @Description: Properties 就是为了读取 *.properties 文件而设计的API，其底层就是文本文件IO.
 * Properties本身实现Map接口,内部是散列表,限定了key和Value都是,String 类型.
 * 方法: load(流) 将文件就读取为散列表，String getProperty(key) 查询value
 */
public class JDBCUtil {

    private JDBCUtil() {
    }

    /*** 基本参数*/
    private static String driverClassName;
    private static String url;
    private static String username;
    private static String password;
    /*** 连接池参数*/
    private static String filters;
    private static int initialSize;
    private static int minIdle;
    private static int maxActive;
    private static int maxWait;
    private static int timeBetweenEvictionRunsMillis;
    private static boolean poolPreparedStatements;
    private static int minEvictableIdleTimeMillis;
    private static int maxOpenPreparedStatements;
    private static boolean testWhileIdle;
    private static boolean testOnBorrow;
    private static boolean testOnReturn;
    /*** 全局变量*/
    private static DruidDataSource druidDataSource = new DruidDataSource();

    /***声明线程共享变量*/
    public static ThreadLocal<Connection> container = new ThreadLocal<Connection>();

    /**
     * 获取数据连接
     */
    public static Connection getConnection() {
        Connection conn = null;
        try {
            System.out.println("druidDataSource:" + druidDataSource);
            conn = druidDataSource.getConnection();
            System.out.println(Thread.currentThread().getName() + "连接已经开启......");
            container.set(conn);
        } catch (Exception e) {
            System.out.println("连接获取失败");
            e.printStackTrace();
        }
        return conn;
    }

    /**
     * 获取当前线程上的连接开启事务
     */
    public static void startTransaction() {
        //首先获取当前线程的连接
        Connection conn = container.get();
        //如果连接为空
        if (conn == null) {
            //从连接池中获取连接
            conn = getConnection();
            //将此连接放在当前线程上
            container.set(conn);
            System.out.println(Thread.currentThread().getName() + "空连接从dataSource获取连接");
        } else {
            System.out.println(Thread.currentThread().getName() + "从缓存中获取连接");
        }
        try {
            //开启事务
            conn.setAutoCommit(false);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 提交事务
     */
    public static void commit() {
        try {
            //从当前线程上获取连接if(conn!=null){//如果连接为空，则不做处理
            Connection conn = container.get();
            if (null != conn) {
                //提交事务
                conn.commit();
                System.out.println(Thread.currentThread().getName() + "事务已经提交......");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * 回滚事务
     */
    public static void rollback() {
        try {
            //检查当前线程是否存在连接
            Connection conn = container.get();
            if (conn != null) {
                //回滚事务
                conn.rollback();
                //如果回滚了，就移除这个连接
                container.remove();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 关闭连接
     */
    public static void close() {
        try {
            Connection conn = container.get();
            if (conn != null) {
                conn.close();
                System.out.println(Thread.currentThread().getName() + "连接关闭");
            }
        } catch (SQLException e) {
            throw new RuntimeException(e.getMessage(), e);
        } finally {
            try {
                container.remove();//从当前线程移除连接切记
            } catch (Exception e2) {
                e2.printStackTrace();
            }
        }
    }

    static {
        try {
            // 1.利用Properties 读取配置文件
            Properties properties = new Properties();
            // 在resource 文件夹中添加配置文件 db.properties
            InputStream inputStream = JDBCUtil.class.getClassLoader().getResourceAsStream("db.properties");
            properties.load(inputStream);

            // 2.获取基本参数
            driverClassName = properties.getProperty("driverClassName");
            url = properties.getProperty("url");
            username = properties.getProperty("username");
            password = properties.getProperty("password");

            // 3.获取连接池参数
            filters = properties.getProperty("druid.filters");
            initialSize = Integer.parseInt(properties.getProperty("druid.initialSize"));
            minIdle = Integer.parseInt(properties.getProperty("druid.minIdle"));
            maxActive = Integer.parseInt(properties.getProperty("druid.maxActive"));
            maxWait = Integer.parseInt(properties.getProperty("druid.maxWait"));
            timeBetweenEvictionRunsMillis = Integer.parseInt(properties.getProperty("druid.timeBetweenEvictionRunsMillis"));
            poolPreparedStatements = Boolean.parseBoolean(properties.getProperty("druid.poolPreparedStatements"));
            minEvictableIdleTimeMillis = Integer.parseInt(properties.getProperty("druid.minEvictableIdleTimeMillis"));
            maxOpenPreparedStatements = Integer.parseInt(properties.getProperty("druid.maxOpenPreparedStatements"));
            testWhileIdle = Boolean.parseBoolean(properties.getProperty("druid.testWhileIdle"));
            testOnBorrow = Boolean.parseBoolean(properties.getProperty("druid.testOnBorrow"));
            testOnReturn = Boolean.parseBoolean(properties.getProperty("druid.testOnReturn"));

        } catch (Exception e) {
            System.out.println("读取配置文件失败...");
            e.printStackTrace();
        }
    }

    static {
        try {
            druidDataSource.setDriverClassName(driverClassName);
            druidDataSource.setUrl(url);
            druidDataSource.setUsername(username);
            druidDataSource.setPassword(password);

            druidDataSource.setFilters(filters);
            druidDataSource.setInitialSize(initialSize);
            druidDataSource.setMinIdle(minIdle);
            druidDataSource.setMaxActive(maxActive);
            druidDataSource.setMaxWait(maxWait);
            druidDataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
            druidDataSource.setPoolPreparedStatements(poolPreparedStatements);
            druidDataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
            druidDataSource.setMaxOpenPreparedStatements(maxOpenPreparedStatements);
            druidDataSource.setTestWhileIdle(testWhileIdle);
            druidDataSource.setTestOnBorrow(testOnBorrow);
            druidDataSource.setTestOnReturn(testOnReturn);
        } catch (Exception e) {
            System.out.println("连接池设置出错...");
            e.printStackTrace();
        }
    }
}
